#ifndef _STREAMER_HPP_20120414
#define _STREAMER_HPP_20120414

#include "base.hpp"
#include "type_trait.hpp"
#include "listbuffer.hpp"

namespace mina
{
	class Streamer
	{
		public :
			enum
			{
				ISTREAMER = 0,
				OSTREAMER = 1,
			};

		public :
			Streamer(uint16_t type, ListBuffer & listbuffer)
				: _type(type),
			      _list_buffer(listbuffer)
			{
			}

			bool in() const { return (ISTREAMER == _type); }

		public :
			uint16_t     _type;

			ListBuffer & _list_buffer;

			template <typename _T>
				Streamer & serialize(_T & val, Int2Type<INT_TYPE>)
				{
					if (Streamer::OSTREAMER == _type)
					{
						_list_buffer.move_to(val);
					}
					else
					{
						_list_buffer.append(val);
					}

					return *this;
				}

			template <typename _T>
				Streamer & serialize(_T & val, Int2Type<STRING_TYPE>)
				{
					if (Streamer::OSTREAMER == _type)
					{
						_list_buffer.move_to_s(val);
					}
					else
					{
						_list_buffer.append_s(val);
					}

					return *this;
				}

			template <typename _T>
				Streamer & serialize(_T & val, Int2Type<USER_TYPE>)
				{
					val.serialize(*this);
					return *this;
				}

			template <typename _T>
				Streamer & serialize(std::vector<_T> & vec)
				{
					uint32_t size = vec.size();

					serialize(size, Int2Type<INT_TYPE>());

					if (OSTREAMER == _type)
					{
						vec.reserve(size);
					}

					for (uint32_t i = 0; i < size; ++ i)
					{
						serialize(vec[i], Int2Type<TypeTrait<_T>::base_type>());
					}

					return *this;
				}

		private :
			Streamer(const Streamer &);
			Streamer & operator = (const Streamer &);
	};

	template <typename _T>
		Streamer & operator & (Streamer & streamer, _T & val)
		{
			return streamer.serialize(val, Int2Type<TypeTrait<_T>::base_type>());
		}

	template <typename _T>
		Streamer & operator & (Streamer & streamer, std::vector<_T> & vec)
		{
			return streamer.serialize(vec);
		}
}

#endif

